#include "XmlFormattedObjectInputStream.h"

namespace Entities {

XmlFormattedObjectInputStream::XmlFormattedObjectInputStream( istream & _in, DOM::Element<string> & root ):
ObjectInputStream(_in), current(root), pos(0) {}

string XmlFormattedObjectInputStream::getObjectName(){
	return current.getAttribute("class");
}

string XmlFormattedObjectInputStream::getObjectIdentifier(){
	return current.getAttribute("id");
}

DOM::Element<string> XmlFormattedObjectInputStream::nextElement(){
	DOM::Element<string> next;
	DOM::Node<string> cur_node = current.getChildNodes().item(++pos);

	while (cur_node!=NULL && cur_node.getNodeType()!=DOM::Node<string>::ELEMENT_NODE){
		cur_node = cur_node.getNextSibling();
		pos++;
	}
	if ( cur_node != NULL ){
		next = (DOM::Element<string>) cur_node;
	}
	return next;
}

DOM::Element<string> XmlFormattedObjectInputStream::previousElement(){
	DOM::Element<string> previous;
	DOM::Node<string> cur_node = current.getChildNodes().item(--pos);

	while (cur_node!=NULL && cur_node.getNodeType()!=DOM::Node<string>::ELEMENT_NODE){
		cur_node = cur_node.getPreviousSibling();
		pos--;
	}
	if ( cur_node != NULL ){
		previous = (DOM::Element<string>) cur_node;
	}
	return previous;
}

bool XmlFormattedObjectInputStream::readObject(Serializable & obj){
	if (current.hasChildNodes() /*&& (
		current.getTagName() == "entity" ||
		current.getTagName() == "module" ||
		current.getTagName() == "container" )*/) {
		
		DOM::Element<string> cur_element = nextElement();
		//cout << current.getTagName() << endl;
		if (cur_element == NULL) return false;
		
		XmlFormattedObjectInputStream xmlIn(in, cur_element);
		obj.load(xmlIn);
		return true;
	} 
	return false;
}

bool XmlFormattedObjectInputStream::readValue(string & value){
	DOM::Element<string> cur_element = nextElement();

	if (cur_element.getTagName() == "value" ) {
		DOM::Node<string> cur_node = cur_element.getFirstChild();
		DOM::CharacterData<string> data = (DOM::CharacterData<string>) cur_node;
		value.assign(data.getData());
		return true;
	}	
	return false;
}

void XmlFormattedObjectInputStream::putback(string & str){
	previousElement();
}

string XmlFormattedObjectInputStream::get(){
	string str;
	readValue(str);
	return str;
}

int XmlFormattedObjectInputStream::available(){
	int next = pos, nbChilds = 0;

	if (current.hasChildNodes()){
		DOM::Node<string> cur_node = current.getChildNodes().item(++next);
		while (cur_node!=NULL){
			while (cur_node!=NULL && cur_node.getNodeType()!=DOM::Node<string>::ELEMENT_NODE){
				cur_node = cur_node.getNextSibling();
				next++;
			}
			if ( cur_node != NULL ){
				nbChilds++;
				cur_node = cur_node.getNextSibling();
				next++;
			}
		}
	}
	return nbChilds;
}

vector<string> XmlFormattedObjectInputStream::getInfos(int idAttributs){
	vector<string> v;
	Attributs a = (Attributs) idAttributs;

	DOM::NodeList<string> childs = current.getElementsByTagName("value");
	for (int i=0; i<childs.getLength(); i++){
		DOM::Element<string> ele = (DOM::Element<string>) childs.item(i);
		string attr;
		switch (a) {
			case min : attr = ele.getAttribute("min");
				break;
			case max : attr = ele.getAttribute("max");
				break;
		}
		if (attr == "") {
			DOM::Node<string> cur_node = ele.getFirstChild();
			DOM::CharacterData<string> data = (DOM::CharacterData<string>) cur_node;
			attr.assign(data.getData());
		}
		v.push_back(attr);
	}
	return v;
}

XmlFormattedObjectInputStream XmlFormattedObjectInputStream::getXmlFormattedObjectInputStream(string & src){
	SAX2DOM::Parser<std::string> domParser;
	SAX::CatchErrorHandler<std::string> eh;
	SAX::InputSource is;

	domParser.setErrorHandler(eh);
	is.setSystemId(src);

	domParser.parse(is);
	DOM::Document<string> doc = domParser.getDocument();
	DOM::Element<string> ele = doc.getDocumentElement();
	return XmlFormattedObjectInputStream(*is.getByteStream(), ele);
}

}